<?php
declare(strict_types=1);

namespace App\Service;

use App\Utils\CustomUtils;
use Hyperf\Di\Annotation\Inject;
use App\Model\Dao\RateBocDao;
use App\Model\Dao\RateBocLogDao;
use App\Exception\XZXValidationException;
use App\Constants\XZXResponseCode;
use App\Utils\ArrayUtils;
use Hyperf\Utils\ApplicationContext;
use Hyperf\Utils\Coroutine;
use App\Utils\DateUtils;
use App\Utils\XzxSimpleHtmlDom;
use App\Service\RateCustomizedService;


class RateBocService
{
    /**
     * @Inject()
     * @var RateBocDao
     */
    private $RateBocDao;
 

    /**
     * @Inject()
     * @var RateBocLogDao
     */
    private $RateBocLogDao;

    public function get($param)
    {
        $result = $this->RateBocDao->get($param['id']);
        if (!$result) {
            throw new XZXValidationException(XZXResponseCode::getMessage(XZXResponseCode::DATA_NOT_FOUND));
        }
        if(isset($result['createTime'])){
            $result['createTime'] = DateUtils::getDateTime($result['createTime']);
        }

        return CustomUtils::xeServiceReturnData(XZXResponseCode::SUCCESS_CODE,XZXResponseCode::getMessage(XZXResponseCode::SUCCESS_CODE),$result);
    }

    public function del($param)
    {
        $result = $this->RateBocDao->get($param['id']);
        if (!$result) {
            throw new XZXValidationException(XZXResponseCode::getMessage(XZXResponseCode::DATA_NOT_FOUND));
        }
        
        try {
            $result = $this->RateBocDao->del($param['id'],false);
        } catch (\Throwable $th) {
            throw new XZXValidationException(XZXResponseCode::getMessage(XZXResponseCode::DEL_FAIL));
        }
        return CustomUtils::xeServiceReturnData(XZXResponseCode::SUCCESS_CODE,XZXResponseCode::getMessage(XZXResponseCode::SUCCESS_CODE),CustomUtils::xzxEmptyObject());
    }

    public function add($param)
    {
        // TODO: Implement add() method.
        //$data            =  [
        //    'name'       => $param['name'],
        //    'desciption' => $param['desciption'],
        //
        //];
        $data = $param;
        CustomUtils::xzxDebug($data);
        
        try {
            $this->RateBocDao->insert($data);
            $log_data = array(
                "id" => CustomUtils::createUUID(),
                "rateBocId" => $data['id'],
                "buyPrice" => $param['buyPrice'],
                "buyRate" => $param['buyRate'],
                "cashBuyPrice" => $param['cashBuyPrice'],
                "cashBuyRate" => $param['cashBuyRate'],
                "sellPrice" => $param['sellPrice'],
                "sellRate" => $param['sellRate'],
                "cashSellPrice" => $param['cashSellPrice'],
                "cashSellRate" => $param['cashSellRate'],
                "bocPrice" => $param['bocPrice'],
                "bocRate" => $param['bocRate'],
                "createTime" => time(),
                "syncTime" => $param['syncTime'],
            );
            $this->RateBocLogDao->add($log_data);            
        } catch (\Throwable $th) {
            CustomUtils::xzxDebug($th);
            throw new XZXValidationException(XZXResponseCode::getMessage(XZXResponseCode::ADD_FAIL));
        }
        return CustomUtils::xeServiceReturnData(XZXResponseCode::SUCCESS_CODE,XZXResponseCode::getMessage(XZXResponseCode::SUCCESS_CODE),CustomUtils::xzxEmptyObject());
    }

    public function edit($param)
    {
        $info = $this->RateBocDao->get($param['id']);
        if (!$info) {
            throw new XZXValidationException(XZXResponseCode::getMessage(XZXResponseCode::DATA_NOT_FOUND));
        }

        $id = $param['id'];
        $data = array();
        // isset($param['name']) && $data['name'] = $param['name'];
        // isset($param['desciption']) && $data['desciption'] = $param['desciption'];

        foreach($param as $k => $v){
            if($k == "id"){
                continue;
            }            
            if(isset($v)){
                $data[$k] = $v;
            }
        }
        CustomUtils::xzxDebug($data);
        
        try {
            $this->RateBocDao->update($id, $data);
            $log_data = array(
                "id" => CustomUtils::createUUID(),
                "rateBocId" => $param['id'],
                "buyPrice" => $param['buyPrice'],
                "buyRate" => $param['buyRate'],
                "cashBuyPrice" => $param['cashBuyPrice'],
                "cashBuyRate" => $param['cashBuyRate'],
                "sellPrice" => $param['sellPrice'],
                "sellRate" => $param['sellRate'],
                "cashSellPrice" => $param['cashSellPrice'],
                "cashSellRate" => $param['cashSellRate'],
                "bocPrice" => $param['bocPrice'],
                "bocRate" => $param['bocRate'],
                "createTime" => time(),
                "syncTime" => $param['syncTime'],
            );
            $result = $this->RateBocLogDao->add($log_data);            
        } catch (\Throwable $th) {
            throw new XZXValidationException(XZXResponseCode::getMessage(XZXResponseCode::EDIT_FAIL));
        }
        return CustomUtils::xeServiceReturnData(XZXResponseCode::SUCCESS_CODE,XZXResponseCode::getMessage(XZXResponseCode::SUCCESS_CODE),CustomUtils::xzxEmptyObject());
    }

    public function list(array $param)
    {

        $limit = $param['limit'];
        $page = $param['page'];        

        $total = $this->RateBocDao->getCount($param);
        $list = $this->RateBocDao->getList($param, $page, $limit);

        CustomUtils::xzxDebug($list);
        foreach ($list as $k => $v) {
            CustomUtils::xzxDebug($v);
            if(isset($v['createTime'])){
                $v['createTime'] = DateUtils::getDateTime($v['createTime']);
                $v['syncTime']   = $v['updateTime'];
            }
            $list[$k] = $v;
        }

        $data = array(
            'total' => $total,
            'list' => $list
        );

        return CustomUtils::xeServiceReturnData(XZXResponseCode::SUCCESS_CODE,XZXResponseCode::getMessage(XZXResponseCode::SUCCESS_CODE),$data);
    }    


    //获取中行汇率
    public function getRate(array $param)
    {
        $type = $param['type'];
        $srcCurrency = $param['srcCurrency'];
        $destCurrency = $param['destCurrency'];

        $standardCurrency = config('standardCurrency');

        $srcBocResult = $this->RateBocDao->getWhere(['currency' => $srcCurrency]);

        // var_dump($srcBocResult);

        if(!$srcBocResult)
        {
            //查找src currency 信息失败
            throw new XZXValidationException('查找src currency 信息失败');
        }

        $bDestCurrencyIsCNY = true;
        if(strcmp($destCurrency, $standardCurrency))
        {
            //目标币种不是CNY
            $destBocResult = $this->RateBocDao->getWhere(['currency' => $destCurrency]);
            
            if(!$destBocResult)
            {
                //查找dest currency 信息失败                    
                throw new XZXValidationException('查找dest currency 信息失败');
            }
            $bDestCurrencyIsCNY = false;
        }

        $data = array();
        switch($type)
        {
            case 1:
                $data['rate'] = $srcBocResult['buyRate'];

                if(!$bDestCurrencyIsCNY)
                {
                    $data['rate'] = $this->calRateBetweenDiffCurrency($srcBocResult['buyPrice'], $destBocResult['buyPrice']);
                }
                //现汇买入价
                break;
            case 2:
                $data['rate'] = $srcBocResult['cashBuyRate'];

                if(!$bDestCurrencyIsCNY)
                {
                    $data['rate'] = $this->calRateBetweenDiffCurrency($srcBocResult['cashBuyPrice'], $destBocResult['cashBuyPrice']);
                }
                //现钞买入价
                break;
            case 3:
                $data['rate'] = $srcBocResult['sellRate'];

                if(!$bDestCurrencyIsCNY)
                {
                    $data['rate'] = $this->calRateBetweenDiffCurrency($srcBocResult['sellPrice'], $destBocResult['sellPrice']);
                }
                //现汇卖出价
                break;
            case 4:
                $data['rate'] = $srcBocResult['cashSellRate'];

                if(!$bDestCurrencyIsCNY)
                {
                    $data['rate'] = $this->calRateBetweenDiffCurrency($srcBocResult['cashSellPrice'], $destBocResult['cashSellPrice']);
                }
                //现钞卖出价
                break;
            case 5:
            default:
                //中行折算价
                $data['rate'] = $srcBocResult['bocRate'];

                if(!$bDestCurrencyIsCNY)
                {
                    $data['rate'] = $this->calRateBetweenDiffCurrency($srcBocResult['bocPrice'], $destBocResult['bocPrice']);
                }
                break;
        }
        return CustomUtils::xeServiceReturnData(XZXResponseCode::SUCCESS_CODE,XZXResponseCode::getMessage(XZXResponseCode::SUCCESS_CODE),$data);
    }

    public function calRateBetweenDiffCurrency($srcCurrencyPrice,$destCurrencyPrice) {
        CustomUtils::xzxDebug($srcCurrencyPrice);
        CustomUtils::xzxDebug($destCurrencyPrice);
        if (!$srcCurrencyPrice || $srcCurrencyPrice == 0) {                
            throw new XZXValidationException('原始币种没有汇率');
        }

        if (!$destCurrencyPrice || $destCurrencyPrice == 0) {
            throw new XZXValidationException('目标币种没有汇率');
        }

        $rateDivisor = config('rateDivisor');
        if($srcCurrencyPrice == $destCurrencyPrice){
            return 1 * 10000;
        }
        // return ceil((($rateDivisor / $destCurrencyPrice) * ($srcCurrencyPrice / $rateDivisor)) * 10000) ; //取最大整数
        bcscale(8);
        return ceil(bcdiv(strval($srcCurrencyPrice * 10000), strval($destCurrencyPrice)));
    }
    
    public function logList(array $param)
    {
        $limit = $param['limit'];
        $page = $param['page'];        

        $total = $this->RateBocLogDao->getCount($param);
        $list = $this->RateBocLogDao->getList($param, $page, $limit);

        CustomUtils::xzxDebug($list);

        $real_result = array();
        $currency_info = $this->RateBocDao->get($param['rateBocId']);

        foreach ($list as $k => $v) {

            if(!$currency_info)
            {
                $v['currency'] = "ZZZ";
            }
            else
            {
                $v['currency'] = $currency_info['currency'];
            }
            if(isset($v['createTime'])){
                $v['createTime'] = DateUtils::getDateTime($v['createTime']);
                $v['syncTime']   = $v['updateTime'];
            }
            // $list[$k] = $v;
            $real_result[] = $v;
        }

        $data = array(
            'total' => $total,
            'list' => $real_result
        );

        return CustomUtils::xeServiceReturnData(XZXResponseCode::SUCCESS_CODE,XZXResponseCode::getMessage(XZXResponseCode::SUCCESS_CODE),$data);
    }

    public function crawler()
    {
        $html = XzxSimpleHtmlDom::file_get_html(env('BOC_CRAWLER_URL'));
        $tmp = array();
        foreach($html->find('.publish') as $e)
        {
            //echo $e->outertext;
            //取这块div内的tr
            $s_html = XzxSimpleHtmlDom::str_get_html($e->outertext);
            $y = 0;
            foreach($s_html->find('tr') as $se)
            {
                // echo $se->outertext;
                //       continue;
                if($y <= 1)
                {
                    //去掉第一和第二条tr
                    $y++;
                    continue;
                }
                //取这条tr内的td
                $ss_html = XzxSimpleHtmlDom::str_get_html($se->outertext);
                $i = 0;
                foreach($ss_html->find('td') as $sse)
                {
//                     echo $sse->plaintext."\r\n";

                    switch($i)
                    {
                        case 0:
                            $tmp[$y]['currencyName'] = $sse->plaintext;
                            $tmp[$y]['currency'] = config('currencyMapping')[$sse->plaintext];
                            $i++;
                            break;
                        case 1:
                            $tmp[$y]['buyPrice'] = !empty($sse->plaintext) ? $sse->plaintext : 0;
                            $i++;
                            break;
                        case 2:
                            $tmp[$y]['cashBuyPrice'] = !empty($sse->plaintext) ? $sse->plaintext : 0;
                            $i++;
                            break;
                        case 3:
                            $tmp[$y]['sellPrice'] = !empty($sse->plaintext) ? $sse->plaintext : 0;
                            $i++;
                            break;
                        case 4:
                            $tmp[$y]['cashSellPrice'] = !empty($sse->plaintext) ? $sse->plaintext : 0;
                            $i++;
                            break;
                        case 5:
                            $tmp[$y]['bocPrice'] = !empty($sse->plaintext) ? $sse->plaintext : 0;
                            $i++;
                            break;
                        case 6:
                            //爬回来的日期是2020.08.05 要转成 yyyy-mm-dd
                            $tmp[$y]['fbrq'] = str_replace('.','-',$sse->plaintext);
                            $i++;
                            break;
                        case 7:
                            //一条tr结束
                            $tmp[$y]['fbsj'] = $sse->plaintext;
                            $i = 0;
                            $y++;
                            break;
                        default:
                            $i = 0;
                            $y++;
                    }
                }
            }
        }
        // xeDebug($tmp);
        // $data = xeArrayKeyst($tmp,'currency');
        $data = ArrayUtils::ArrayKeyst($tmp,'currency');
        // xeDebug($data);
        foreach ($data as $v)
        {
            $param = array();
            $param = array(
                'id'            => CustomUtils::createUUID(),
                "currency"      => $v['currency'],
                "buyPrice"      => $v['buyPrice'] * 10000,
                "cashBuyPrice"  => $v['cashBuyPrice'] * 10000,
                "sellPrice"     => $v['sellPrice'] * 10000,
                "cashSellPrice" => $v['cashSellPrice'] * 10000,
                "bocPrice"      => $v['bocPrice'] * 10000,
                "status"        => 1,
                "syncTime"      => strtotime($v['fbrq']),
            );

            $param['buyRate'] = $this->calBocRate($param['buyPrice']);
            $param['cashBuyRate'] = $this->calBocRate($param['cashBuyPrice']);
            $param['sellRate'] = $this->calBocRate($param['sellPrice']);
            $param['cashSellRate'] = $this->calBocRate($param['cashSellPrice']);
            $param['bocRate'] = $this->calBocRate($param['bocPrice']);

            // xeDebug($param);
            // $result = $this->RateBocDao->getInfoByCurrency($param['currency']);
            $queryParam = array(
                'currency' => $param['currency']
            );
            $result = $this->RateBocDao->getWhere($queryParam);
            if(!$result)
            {
                $this->add($param);
            }
            else
            {
                $param['id'] = $result['id'];
                $this->edit($param);
            }

            // 更新汇率定制表
            // $this->RateCustomizedService->syncRate($param["currency"]);
            ApplicationContext::getContainer()->get(RateCustomizedService::class)->syncRate($param["currency"]);
        }
        //造一条CNY的中行汇率
        $param = array();
        $param = array(
            'id'            => CustomUtils::createUUID(),
            "currency"      => 'CNY',
            "buyPrice"      => 100*10000,
            "cashBuyPrice"  => 100*10000,
            "sellPrice"     => 100*10000,
            "cashSellPrice" => 100*10000,
            "bocPrice"      => 100*10000,
            "status"        => 1,
            "syncTime"      => time(),
        );
        $param['buyRate'] = $this->calBocRate($param['buyPrice']);
        $param['cashBuyRate'] = $this->calBocRate($param['cashBuyPrice']);
        $param['sellRate'] = $this->calBocRate($param['sellPrice']);
        $param['cashSellRate'] = $this->calBocRate($param['cashSellPrice']);
        $param['bocRate'] = $this->calBocRate($param['bocPrice']);
        // $result = $this->RateBocDao->getInfoByCurrency($param['currency']);
        $queryParam = array(
            'currency' => $param['currency']
        );
        $result = $this->RateBocDao->getWhere($queryParam);
        // CustomUtils::xzxDebug($result);
        if(!$result)
        {
            $this->add($param);
        }
    }

    private function calBocRate($price)
    {
        //前端显示的时候汇率保留两位小数 所以这里乘以 10000
        return ceil(($price / config('rateDivisor')) * 10000);
    }    

}